package cn.lj.service.impl;

import cn.lj.entity.Menu;
import cn.lj.entity.Role;
import cn.lj.entity.User;
import cn.lj.mapper.UserMapper;
import cn.lj.service.MenuService;
import cn.lj.service.RoleService;
import cn.lj.service.UserService;
import cn.lj.utils.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 李津
 * @since 2021-05-19
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final RedisUtil redisUtil;
    private final RoleService roleService;
    private final MenuService menuService;

    @Autowired
    public UserServiceImpl(RedisUtil redisUtil, RoleService roleService, MenuService menuService) {
        this.redisUtil = redisUtil;
        this.roleService = roleService;
        this.menuService = menuService;
    }

    @Override
    public User getByUserName(String username) {
        return getOne(new QueryWrapper<User>().eq("username",username));
    }

    /**
     * 获取用户权限信息（角色、菜单权限）
     * @param userId
     * @return
     */
    @Override
    public String getUserAuthorityInfo(Long userId) {

        User sysUser = this.baseMapper.selectById(userId);

        //  ROLE_admin,ROLE_normal,sys:user:list,....
        String authority = "";

        //判断redis是否缓存了用户权限
        if (redisUtil.hasKey("GrantedAuthority:" + sysUser.getUsername())) {
            authority = (String) redisUtil.get("GrantedAuthority:" + sysUser.getUsername());
        } else {
            // 获取角色编码 ROLE_admin,ROLE_normal
            List<Role> roles = roleService.list(new QueryWrapper<Role>()
                    .inSql("id", "select role_id from sys_user_role where user_id = " + userId));

            if (roles.size() > 0) {
                String roleCodes = roles.stream().map(r -> "ROLE_" + r.getCode()).collect(Collectors.joining(","));
                authority = roleCodes.concat(",");
            }

            // 获取菜单操作编码 sys:user:list,....
            List<Long> menuIds = this.baseMapper.getNavMenuIds(userId);
            if (menuIds.size() > 0) {

                List<Menu> menus = menuService.listByIds(menuIds);
                String menuPerms = menus.stream().map(Menu::getPerms).collect(Collectors.joining(","));

                authority = authority.concat(menuPerms);
            }

            //权限缓存
            redisUtil.set("GrantedAuthority:" + sysUser.getUsername(), authority, 60 * 60);
        }

        return authority;
    }

    /**
     * 权限缓存的实时更新问题，比如当后台更新某个管理员的权限角色信息的时候如果权限缓存信息没有实时更新，就会出现操作无效的问题
     * 那么我们现在点定义几个方法，用于清除某个用户或角色或者某个菜单的权限的方法
     * 第一种情况：user发生改变,需要删除redis用户权限
     * @param username
     */
    @Override
    public void clearUserAuthorityInfo(String username) {
        redisUtil.del("GrantedAuthority:" + username);
    }

    /**
     * 第二种情况：role发生改变,需要删除所有与该角色关联的用户的权限信息
     * @param roleId
     */
    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {
        List<User> sysUsers = this.list(new QueryWrapper<User>()
                .inSql("id", "select user_id from sys_user_role where role_id = " + roleId));

        sysUsers.forEach(u -> this.clearUserAuthorityInfo(u.getUsername()));
    }

    /**
     * 第三种情况：menu发生改变,需要删除删除所有与该菜单关联的所有用户的权限信息
     * @param menuId
     */
    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        List<User> sysUsers = this.baseMapper.listByMenuId(menuId);

        sysUsers.forEach(u -> this.clearUserAuthorityInfo(u.getUsername()));

    }
}
